package com.jfinal.plugin.memcache;

import net.dreamlu.config.Consts;
import net.dreamlu.utils.ConfigUtil;

import com.baidu.bae.api.memcache.BaeMemcachedClient;

/**
 * BAE memcache 整合
 * @author L.cm
 * @date 2013-6-2 下午9:04:58
 * <url>http://javasdk.duapp.com/?com/baidu/bae/api/memcache/BaeMemcachedClient.html</url>
 */
public class MemCacheKit {

	private static BaeMemcachedClient cachedClient = new BaeMemcachedClient();
	
	static{
		cachedClient.setAk(Consts.AK);
		cachedClient.setSk(Consts.SK);
	}
	
	static void init(BaeMemcachedClient cachedClient) {
		MemCacheKit.cachedClient = cachedClient;
	}

	public static BaeMemcachedClient getCachedClient() {
		return cachedClient;
	}

	/**
     * Adds data to the server; only the key and the value are specified.
     *
     * @param key key to store data under
     * @param value value to store
     * @return true, if the data was successfully stored
     */
	public static boolean put(String key, Object value) {
		return cachedClient.add(key, value);
	}
	
	/**
     * Adds data to the server; the key, value, and an optional hashcode are passed in.
     *
     * @param key key to store data under
     * @param value value to store
     * @param hashCode if not null, then the int hashcode to use
     * @return true, if the data was successfully stored
     */
	public static boolean put(String key, Object value, long expiry) {
		return cachedClient.add(key, value, expiry);
	}
	
	/**
     * Stores data on the server; only the key and the value are specified.
     *
     * @param key key to store data under
     * @param value value to store
     * @return true, if the data was successfully stored
     */
	public static boolean update(String key, Object value) {
		return cachedClient.set(key, value);
	}
	
	/**
     * Retrieve a key from the server, using a specific hash.
     *
     *  If the data was compressed or serialized when compressed, it will automatically<br/>
     *  be decompressed or serialized, as appropriate. (Inclusive or)<br/>
     *  <br/>
     *  Non-serialized data will be returned as a string, so explicit conversion to<br/>
     *  numeric types will be necessary, if desired<br/>
     *
     * @param key key where data is stored
     * @return the object that was previously stored, or null if it was not previously stored
     */
	@SuppressWarnings("unchecked")
	public static <T> T get(String key) {
		return (T) cachedClient.get(key);
	}
	
	/**
     * Deletes an object from cache given cache key, a delete time, and an optional hashcode.
     *
     *  The item is immediately made non retrievable.<br/>
     *  Keep in mind {@link #add(String, Object) add} and {@link #replace(String, Object) replace}<br/>
     *  will fail when used with the same key will fail, until the server reaches the<br/>
     *  specified time. However, {@link #set(String, Object) set} will succeed,<br/>
     *  and the new value will not be deleted.
     *
     * @param key the key to be removed
     * @param hashCode if not null, then the int hashcode to use
     * @param expiry when to expire the record.
     * @return <code>true</code>, if the data was deleted successfully
     */
	public static boolean remove(String key) {
		return cachedClient.delete(key);
	}
	
	/** 
     * Checks to see if key exists in cache. 
     * 
     * @param key the key to look for
     * @return true if key found in cache, false if not (or if cache is down)
     */
	public static boolean exists(String key) {
	    return cachedClient.keyExists(key);
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T get(String key, IDataLoader dataLoader) {
		Object data = get(key);
		if (data == null) {
			data = dataLoader.load();
			put(key, data);
		}
		return (T)data;
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T get(String key, Class<? extends IDataLoader> dataLoaderClass) {
		Object data = get(key);
		if (data == null) {
			try {
				IDataLoader dataLoader = dataLoaderClass.newInstance();
				data = dataLoader.load();
				put(key, data);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return (T)data;
	}
}
